package com.hy.stack.monotoneStack;

import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;

public class MonotoneStack {

    /**
     * 739. 每日温度
     * 力扣题目链接
     *
     * 请根据每日 气温 列表，重新生成一个列表。对应位置的输出为：要想观测到更高的气温，至少需要等待的天数。如果气温在这之后都不会升高，请在该位置用 0 来代替。
     *
     * 例如，给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73]，你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
     *
     * 提示：气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度，都是在 [30, 100] 范围内的整数。
     *
     * 通常是一维数组，要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置，此时我们就要想到可以用单调栈了。
     *
     * 时间复杂度为O(n)。
     *
     * 例如本题其实就是找找到一个元素右边第一个比自己大的元素。
     *
     * 此时就应该想到用单调栈了。
     *
     * 那么单调栈的原理是什么呢？为什么时间复杂度是O(n)就可以找到每一个元素的右边第一个比它大的元素位置呢？
     *
     * 单调栈的本质是空间换时间，因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素高的元素，优点是只需要遍历一次。
     *
     * 在使用单调栈的时候首先要明确如下几点：
     *
     * 1.单调栈里存放的元素是什么？
     * 单调栈里只需要存放元素的下标i就可以了，如果需要使用对应的元素，直接T[i]就可以获取。
     *
     * 2.单调栈里元素是递增呢？ 还是递减呢？
     * 注意一下顺序为 从栈头到栈底的顺序，因为单纯的说从左到右或者从前到后，不说栈头朝哪个方向的话，大家一定会越看越懵。
     *
     * 这里我们要使用递增循序（再强调一下是指从栈头到栈底的顺序），因为只有递增的时候，加入一个元素i，才知道栈顶元素在数组中右面第一个比栈顶元素大的元素是i。
     *
     * 文字描述理解起来有点费劲，接下来我画了一系列的图，来讲解单调栈的工作过程。
     *
     * 使用单调栈主要有三个判断条件。
     *
     * 当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况
     * 当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况
     * 当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况
     * @param temperatures
     * @return
     */
    // 版本1
    public static int [] dailyTemperatures(int [] temperatures){
        int len = temperatures.length;
        int [] res = new int[len];
        Deque<Integer> stack = new LinkedList<>();
        stack.push(0);
        for (int i = 0; i < len; i++) {
            if (temperatures[i] <= temperatures[stack.peek()]){
                stack.push(i);
            }else {
                while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]){
                    res[stack.peek()] = i - stack.peek();
                    stack.pop();
                }
                stack.push(i);
            }
        }
        return res;
    }

    // 版本二
    public static int [] dailyTemperatures02(int [] temperatures){
        int len = temperatures.length;
        int [] res = new int[len];
        Deque<Integer> deque = new LinkedList<>();
        for (int i = 0; i < len; i++) {
            while (!deque.isEmpty() && temperatures[i] > temperatures[deque.peek()]){
                res[deque.peek()] = i - deque.peek();
                deque.pop();
            }
            deque.push(i);
        }
        return res;
    }

    public static void main(String[] args) {
        int [] temperatures = {73, 74, 75, 71, 69, 72, 76, 73};
        System.out.println("res: "+ Arrays.toString(dailyTemperatures(temperatures)));
        System.out.println("res: "+ Arrays.toString(dailyTemperatures02(temperatures)));
    }
}
